package cn.tedu.knows.sys.service.impl;


import cn.tedu.knows.commons.exception.ServiceException;
import cn.tedu.knows.commons.model.*;
import cn.tedu.knows.sys.mapper.ClassroomMapper;
import cn.tedu.knows.sys.mapper.UserMapper;
import cn.tedu.knows.sys.mapper.UserRoleMapper;
import cn.tedu.knows.sys.service.IUserService;
import cn.tedu.knows.sys.vo.RegisterVo;
import cn.tedu.knows.sys.vo.UserVo;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author tedu.cn
 * @since 2021-05-25
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    //注入所有需要连接数据库的Mapper依赖
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private ClassroomMapper classroomMapper;
    @Autowired
    private UserRoleMapper userRoleMapper;

    @Override
    public void registerStudent(RegisterVo registerVo) {

        //1.根据用户输入的邀请码查询班级信息
        QueryWrapper<Classroom> query=new QueryWrapper<>();
        query.eq("invite_code"
                                ,registerVo.getInviteCode());
        Classroom classroom=classroomMapper.selectOne(query);
        log.debug("邀请码对应班级为:{}",classroom);
        //2.判断班级是否存在
        if(classroom==null){
            throw new ServiceException("邀请码错误!");
        }
        //3.根据用户输入的用户名判断用户是否已经注册
        User u=userMapper.findUserByUsername(
                                    registerVo.getPhone());
        if(u!=null){
            throw new ServiceException("手机号已经被注册");
        }
        //4.实例化加密算法对象
        PasswordEncoder encoder=new BCryptPasswordEncoder();
        //5.实例化User对象,并对必要属性赋值
        User user=new User();
        user.setUsername(registerVo.getPhone())
                .setNickname(registerVo.getNickname())
                .setPassword("{bcrypt}"+
                        encoder.encode(registerVo.getPassword()))
                .setClassroomId(classroom.getId())
                .setCreatetime(LocalDateTime.now())
                .setEnabled(1)
                .setLocked(0)
                .setType(0);
        //6.执行User对象的新增
        int num=userMapper.insert(user);
        //7.判断新增结果
        if(num!=1){
            throw new ServiceException("新增失败!");
        }
        log.debug("新增的用户为:{}",user);
        //8.新增用户和学生角色的关系
        UserRole userRole=new UserRole();
        userRole.setUserId(user.getId())
                .setRoleId(2);
        num=userRoleMapper.insert(userRole);
        if(num!=1){
            throw new ServiceException("新增失败!");
        }
        log.debug("新增用户关系:{}",userRole);
    }


    //两个缓存对象:一个List一个Map
    private List<User> teachers=new CopyOnWriteArrayList<>();
    private Map<String,User> teacherMap=
                        new ConcurrentHashMap<>();

    //开发每隔10分钟清空一次缓存的代码
    private Timer timer=new Timer();

    {
        //这个是初始化代码块,在实例化对象,
        // 构造方法运行前会运行这个代码块中的代码
        //使用计时器创建计时任务,每隔10分钟运行一次,周期调用
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                synchronized (teachers){
                    teachers.clear();
                    teacherMap.clear();
                }
                log.debug("缓存已清空!");
            }
        },1000*60*10,1000*60*10);
    }

    @Resource
    RedisTemplate<String,List<User>> redisTemplate;

    @Override
    public List<User> getTeachers() {
        /*List<User> teachers=redisTemplate
                .opsForValue().get("teachers");
        if(teachers==null){
            QueryWrapper<User> query = new QueryWrapper<>();
            query.eq("type", 1);//type值为1的表示是老师
            List<User> list = userMapper.selectList(query);
            teachers=list;
            redisTemplate.opsForValue().set("teachers",list);
        }*/


        if(teachers.isEmpty()) {
            synchronized (teachers) {
                if(teachers.isEmpty()) {
                    QueryWrapper<User> query = new QueryWrapper<>();
                    query.eq("type", 1);//type值为1的表示是老师
                    List<User> list = userMapper.selectList(query);
                    //将查询出的list赋值到teachers中
                    teachers.addAll(list);
                    //赋值到Map中
                    for(User u: list){
                        teacherMap.put(u.getNickname(),u);
                        //脱敏(将对象中的敏感信息清除)
                        u.setPassword("");
                    }
                }
            }
        }
        //别忘了返回所有老师
        return teachers;
    }

    @Override
    public Map<String, User> getTeacherMap() {
        if(teacherMap.isEmpty()){
            getTeachers();
        }
        return teacherMap;
    }

    @Resource
    private RestTemplate restTemplate;
    @Override
    public UserVo getCurrentUserVo(String username) {
        //查询用户信息
        UserVo userVo=userMapper
                .findUserVoByUsername(username);
        //查询当前用户提问数
        String url="http://faq-service/v1/questions/" +
                "count?userId={1}";
        Integer count=restTemplate.getForObject(url,
                        Integer.class,userVo.getId());
        //问题数赋值给UserVo
        userVo.setQuestions(count);
        //作业:查询当前登录用户的收藏数...

        //别忘了返回
        return userVo;
    }

    @Override
    public User getUserByUsername(String username) {
        return userMapper.findUserByUsername(username);
    }
    @Override
    public List<Permission> getUserPermissions(Integer userId) {
        return userMapper.findUserPermissionsById(userId);
    }
    @Override
    public List<Role> getUserRoles(Integer userId) {
        return userMapper.findUserRolesById(userId);
    }
}
